#include "ComponentHerdBehavior.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "Components/ComponentLocomotion.h"
#include "Components/ComponentHealth.h"

#include "ComponentPathfinding.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemTimeOfDay.h"
#include "Subsystems/SubsystemAnimalEntities.h"

#include "GameRandom.hpp"
#include "Engine/MathUtils.hpp"
#include "Log.h"

#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"

#include <iostream>

namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentHerdBehavior::StateMachine::StateMachine(ComponentHerdBehavior *herdBehavior) : m_herdBehavior(herdBehavior), EasyMachine(MachineState::Inactive) {}

    void ComponentHerdBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Stuck:
            if (GameSingleton::gameRandom->getBool(0.5f))
            {
                m_herdBehavior->m_importanceLevel = 0.0f;
            }
            break;
        case MachineState::Herd:
            MACHINE_DELEGATE()
            {
                Vector3 vector = m_herdBehavior->findHerdCenter();
                Vector3 position;
                m_herdBehavior->componentCreature->componentBody->getPosition(position);

                if (vector != FastVector3::Zero && Vector3::Distance(position, vector) > 6.0f)
                {
                    float speed = (m_herdBehavior->m_importanceLevel > 10.0f) ? GameSingleton::gameRandom->getFloat(0.9f, 1.0f) : GameSingleton::gameRandom->getFloat(0.25f, 0.35f);
                    int32_t maxPathfindingPositions = (m_herdBehavior->m_importanceLevel > 200.0f) ? 100 : 0;
                    m_herdBehavior->componentPathfinding->setDestination(vector, speed, 7.0f, maxPathfindingPositions, false, true, false, nullptr);
                }
                else
                {
                    m_herdBehavior->m_importanceLevel = 0.0f;
                }
            }
            break;
        }
    }

    void ComponentHerdBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            MACHINE_DELEGATE()
            {
                if (m_herdBehavior->subsystemTimeOfDay->periodicGameTimeEvent(1.0f, 0))
                {
                    Vector3 vector2 = m_herdBehavior->findHerdCenter();
                    if (vector2 != FastVector3::Zero)
                    {
                        Vector3 position;
                        m_herdBehavior->componentCreature->componentBody->getPosition(position);

                        float num = Vector3::Distance(vector2, position);
                        if (num > 20.0f)
                        {
                            m_herdBehavior->m_importanceLevel = 250.0f;
                        }
                        else if (num > 16.0f)
                        {
                            m_herdBehavior->m_importanceLevel = 50.0f;
                        }
                        else if (num > 12.0f)
                        {
                            m_herdBehavior->m_importanceLevel = 3.0f;
                        }
                        else if (num > 10.0f)
                        {
                            m_herdBehavior->m_importanceLevel = 1.0f;
                        }
                    }
                    if (m_herdBehavior->isActive())
                    {
                        changeTo(MachineState::Herd);
                    }
                }
            }
            break;
        case MachineState::Stuck:
            MACHINE_DELEGATE()
            {
                changeTo(MachineState::Herd);
            }
            break;
        case MachineState::Herd:
            MACHINE_DELEGATE()
            {
                m_herdBehavior->componentCreature->componentLocomotion->lookOrder = m_herdBehavior->m_look - m_herdBehavior->componentCreature->componentLocomotion->lookAngles;
                if (m_herdBehavior->componentPathfinding->isStuck)
                {
                    changeTo(MachineState::Stuck);
                }
                if (m_herdBehavior->componentPathfinding->destination == FastVector3::Zero)
                {
                    m_herdBehavior->m_importanceLevel = 0.0f;
                }
                if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.05f * dt)
                {
                    // 播放声音
                }
                if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 1.5f * dt)
                {
                    m_herdBehavior->m_look = Vector2(MathUtils::DegToRad(45.0f) * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f), MathUtils::DegToRad(10.0f) * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f));
                }
            }
            break;
        }
    }

    void ComponentHerdBehavior::StateMachine::leave() {}

    // **************************************



    ComponentHerdBehavior::~ComponentHerdBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentHerdBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }

    void ComponentHerdBehavior::callNearbyCreaturesHelp(entt::entity target, float maxRange, float maxChaseTime, bool isPersistent)
    {
        if (GameSingleton::gameRegistry->valid(target))
        {
            ComponentHerdBehavior **herdPtr = GameSingleton::gameRegistry->try_get<ComponentHerdBehavior*>(target);
            if (herdPtr != nullptr)
            {
                ComponentHerdBehavior *herd = *herdPtr;

                Vector3 herdPosition;
                Vector3 position;
                herd->componentCreature->componentBody->getPosition(herdPosition);
                componentCreature->componentBody->getPosition(position);


                if (herd->herdName == herdName &&
                    herd->m_autoNearbyCreaturesHelp &&
                    Vector3::Distance(herdPosition, position) < 256.0f)
                {
                    // ComponentChaseBehavior 待完成...
                }
            }
        }
    }

    Vector3 ComponentHerdBehavior::findHerdCenter()
    {
        if (herdName == "")
        {
            return FastVector3::Zero;
        }
        Vector3 position;
        componentCreature->componentBody->getPosition(position);

        int32_t num = 0;
        Vector3 zero = FastVector3::Zero;
        
        const std::set<entt::entity> entitySet = m_animalEntities->getAnimalEntitySet();
        for (entt::entity entity : entitySet)
        {
            if (GameSingleton::gameRegistry->valid(entity))
            {
                ComponentHerdBehavior **herdPtr = GameSingleton::gameRegistry->try_get<ComponentHerdBehavior*>(entity);
                if (herdPtr != nullptr)
                {
                    ComponentHerdBehavior *herd = *herdPtr;
                    if (herd->componentCreature->componentHealth->health > 0.0f && herd->herdName == herdName)
                    {
                        Vector3 position2;
                        herd->componentCreature->componentBody->getPosition(position2);

                        if (Vector3::DistanceSquared(position, position2) < m_herdingRange * m_herdingRange)
                        {
                            zero += position2;
                            num++;
                        }
                    }
                }
            }
        }

        if (num > 0)
        {
            return zero / num;
        }
        return FastVector3::Zero;
    }



    void ComponentHerdBehavior::update(float dt)
    {
        m_stateMachine->update(dt);
    }

    static const std::string componentName = "HerdBehavior";
    const std::string &ComponentHerdBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentHerdBehavior::GetName()
    {
        return componentName;
    }
    void ComponentHerdBehavior::load(const nlohmann::json &jsonData)
    {
        componentCreature    = GameSingleton::gameRegistry->get<ComponentCreature *>(entity);
        componentPathfinding = GameSingleton::gameRegistry->get<ComponentPathfinding *>(entity);

        subsystemTimeOfDay = GameSingleton::singletonPtr->getSingleton<SubsystemTimeOfDay>();
        m_animalEntities = GameSingleton::singletonPtr->getSingleton<SubsystemAnimalEntities>();

        componentCreature->componentHealth->addAttackedEvent([this](entt::entity attacker)
        {
            callNearbyCreaturesHelp(attacker, 20.0f, 30.0f, false);
        });


        m_stateMachine = new StateMachine(this);
    }

}
